﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Windows.Forms;

namespace vCrossPost.PingFM
{
    public class Api
    {
        private readonly string _devKey;
        private readonly string _userKey;
        private readonly WebClientEx _webClient;

        /// <summary>
        /// Gets the developer API key.
        /// </summary>
        /// <value>The developer API key.</value>
        public string DevKey
        {
            get { return _devKey; }
        }

        /// <summary>
        /// Gets the user API key.
        /// </summary>
        /// <value>The user API key.</value>
        public string UserKey
        {
            get { return _userKey; }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Api"/> class.
        /// </summary>
        /// <param name="devKey">The developer API key.</param>
        /// <param name="userKey">The user API key.</param>
        public Api(string devKey, string userKey)
        {
            if (devKey == null) throw new ArgumentNullException("devKey");
            if (userKey == null) throw new ArgumentNullException("userKey");

            _devKey = devKey;
            _userKey = userKey;
            _webClient = new WebClientEx();
        }

        /// <summary>
        /// Gets the latest messages.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <returns></returns>
        public ICollection<Message> GetLatestMessages(SortOrder order)
        {
            return GetLatestMessages(-1, order);
        }

        /// <summary>
        /// Gets the latest messages.
        /// </summary>
        /// <param name="limit">The limit.</param>
        /// <returns></returns>
        public ICollection<Message> GetLatestMessages(int limit)
        {
            return GetLatestMessages(limit, SortOrder.None);
        }

        /// <summary>
        /// Gets the latest messages.
        /// </summary>
        /// <returns></returns>
        public ICollection<Message> GetLatestMessages()
        {
            return GetLatestMessages(-1, SortOrder.None);
        }

        /// <summary>
        /// Gets the latest messages.
        /// </summary>
        /// <param name="limit">Maximum number of messages returned.</param>
        /// <param name="order">Which direction to order the returned results by date.</param>
        /// <returns></returns>
        public ICollection<Message> GetLatestMessages(int limit, SortOrder order)
        {
            var values = GetStandardValues();

            if (limit > 0)
                values.Add("limit", limit.ToString());

            switch (order)
            {
                case SortOrder.Ascending:
                    values.Add("order", "ASC");
                    break;

                case SortOrder.Descending:
                    values.Add("order", "DESC");
                    break;
            }

            var result = _webClient.ExecuteMethod<LatestResponse>("user.latest", values);

            if (result == null || result.Messages.Count == 0)
                return new Message[0];

            return result.Messages;
        }

        /// <summary>
        /// Gets the system services.
        /// </summary>
        /// <returns></returns>
        public ICollection<Service> GetSystemServices()
        {
            var values = GetStandardValues();
            var services = _webClient.ExecuteMethod<ServicesResponse>("system.services", values);

            if (services == null || services.Services.Count == 0)
                return new Service[0];

            return services.Services;
        }

        /// <summary>
        /// Gets the user services.
        /// </summary>
        /// <returns></returns>
        public ICollection<Service> GetUserServices()
        {
            var values = GetStandardValues();
            var services = _webClient.ExecuteMethod<ServicesResponse>("user.services", values);

            if (services == null || services.Services.Count == 0)
                return new Service[0];

            return services.Services;
        }

        /// <summary>
        /// Posts the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>
        /// 	<c>true</c> if posted; otherwise, <c>false</c>.
        /// </returns>
        public bool Post(PostMessage message)
        {
            return Post(message, false);
        }

        /// <summary>
        /// Posts the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="useChecksum">if set to <c>true</c> checksum will be added for payload.</param>
        /// <returns>
        /// 	<c>true</c> if posted; otherwise, <c>false</c>.
        /// </returns>
        public bool Post(PostMessage message, bool useChecksum)
        {
            var values = GetStandardValues();
            message.CopyTo(values);

            if (useChecksum)
                values["checksum"] = Serialization.GetChecksum(values);

            var ping = _webClient.ExecuteMethod<PingResponse>("user.post", values);
            return ping != null && ping.Status == "OK";
        }

        /// <summary>
        /// Checks if <see cref="DevKey"/> and <see cref="UserKey"/> is valid.
        /// </summary>
        /// <returns></returns>
        public bool Validate()
        {
            var values = GetStandardValues();
            var ping = _webClient.ExecuteMethod<PingResponse>("user.validate", values);

            return ping != null && ping.Status == "OK";
        }

        /// <summary>
        /// Gets a new instance of <see cref="NameValueCollection"/>
        /// with developer API key and user API key filled in.
        /// </summary>
        /// <returns></returns>
        protected NameValueCollection GetStandardValues()
        {
            return new NameValueCollection
            {
                {"api_key", _devKey},
                {"user_app_key", _userKey}
            };
        }
    }
}